import 'dart:async';
import 'dart:isolate';
import 'dart:io';

import 'package:flutter/foundation.dart';

/// 关于线程知识
class IsolateUtils {
  /// 第一种方式：创建一个线程isolate
  /// SendPort对象不用单独创建，它已经包含在ReceivePort对象之中。
  /// 一对Port对象只能单向发消息。
  /// 特别需要注意：createIsolate执行环境是rootIsolate(main isolate)
  static void handleLongTimeMethod(int n) async {
    /// 第1步: 默认执行环境下是rootIsolate，所以创建的是一个rootIsolateReceivePort
    ReceivePort rootIsolateReceivePort = ReceivePort();

    /// 第2步: 获取rootIsolateSendPort
    SendPort rootIsolateSendPort = rootIsolateReceivePort.sendPort;

    /// 第3步: 创建一个newIsolate实例，并把rootIsolateSendPort作为参数传入到newIsolate中，为的是让newIsolate中持有rootIsolateSendPort, 这样在newIsolate中就能向rootIsolate发送消息了
    Isolate newIsolate = await Isolate.spawn(_doJiSuanCount, rootIsolateSendPort);

    /// 第7步: 通过rootIsolateReceivePort接收到来自newIsolate的消息，所以可以注意到这里是await 因为是异步消息
    // -- 只不过这个接收到的消息是newIsolateSendPort, 最后赋值给全局newIsolateSendPort，这样rootIsolate就持有newIsolate的SendPort --
    /* 一 */
    /* rootIsolateReceivePort.listen((message) {
      if (message is SendPort) {
        /// 发送，并在子线程中执行耗时操作
        message.send(n);
      } else if (message is int) {
        /// 耗时结果
        print("耗时结果：$message");

        /// 用完立刻杀死Isolate
        newIsolate.kill(priority: Isolate.immediate);
      }
    }); */

    /// 另一种方式接受，处理函数有返回值
    SendPort newIsolateSendPort = rootIsolateReceivePort.first as SendPort;

    ReceivePort otherReceivePort = ReceivePort();
    newIsolateSendPort.send([n, otherReceivePort.sendPort]);

    /// otherReceivePort接收
    var rs = otherReceivePort.first;

    rootIsolateReceivePort.listen((message) {
      /// 用完立刻杀死Isolate
      newIsolate.kill(priority: Isolate.immediate);
    });

    return rs;
  }

  /// 特别需要注意：_doJiSuanCount执行环境是newIsolate
  static void _doJiSuanCount(SendPort rootIsolateSendPort) async {
    /// 第4步: 注意callback这个函数执行环境就会变为newIsolate, 所以创建的是一个newIsolateReceivePort
    ReceivePort newIsolateReceivePort = ReceivePort();

    /// 第5步: 获取newIsolateSendPort, 注意这里执行环境不是rootIsolate
    SendPort newIsolateSendPort = newIsolateReceivePort.sendPort;

    /// 第6步: 特别需要注意这里，这里是利用rootIsolateSendPort向rootIsolate发送消息，只不过发送消息是newIsolate的SendPort, 这样rootIsolate就能拿到newIsolate的SendPort
    /* 一 */
    rootIsolateSendPort.send(newIsolateSendPort);

    /// 子线程接收
    /* 一 */
    // int n = await newIsolateReceivePort.first as int;

    /// 另一种接受方式
    /* 一 */
    /* newIsolateReceivePort.listen((message) {
      if (message is int) {
        /// 进行耗时操作
        int rs = summ(n);

        /// 回执到主线程
        rootIsolateSendPort.send(rs);
      }
    }); */

    List list = await newIsolateReceivePort.first as List;
    int n = list[0] as int;
    SendPort otherSender = list[1] as SendPort;

    /// 进行耗时操作
    int rs = summ(n);

    /* other 函数返回值 */
    otherSender.send(rs);

    /// 回执到主线程, 杀掉isolate
    /* 一 */
    // rootIsolateSendPort.send(rs);

    rootIsolateSendPort.send('');
  }

  /// 第二种方式创建 Isolate
  /// compute函数有两个必须的参数：
  /// 第一个是待执行的函数，这个函数必须是一个顶级函数，不能是类的实例方法，可以是类的静态方法。
  /// 第二个参数为动态的消息类型，可以是被运行函数的参数。
  /// 需要注意，使用compute应导入’package:flutter/foundation.dart’包。
  static void createIsolateWithConmpute(int n) async {
    var result = await compute(_doTaskWithCompute, {
      "account": "857329255",
      "password": 123456,
      "isRemember": false,
      'n': n,
    });

    print("返回结果：$result");
  }

  static String _doTaskWithCompute(Map<String, dynamic> map) {
    String name = map["account"] ?? "unknown";
    int password = map["password"] ?? -1;
    bool isRemember = map["isRemember"] ?? false;
    int n = map['n'] ?? 0;

    // 模拟耗时
    int rs = summ(n);

    return "complete：$name + $password + $isRemember + 耗时结果：$rs";
  }

  /// 计算0到 num 数值的总和
  static int summ(int num) {
    int count = 0;
    while (num > 0) {
      count = count + num;
      num--;
    }
    return count;
  }
}
